﻿using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using Animoso.Domain.Data;
using NHibernate;
using NHibernate.Criterion;
using NHibernate.Exceptions;
using DataException = System.Data.DataException;

namespace Animoso.Data
{
    public class BaseRepository<T> : IRepository<T>
    {
        private void Validate(T domainObject)
        {
            ValidationContext context = new ValidationContext(domainObject, null, null);
            Validator.ValidateObject(domainObject, context);
        }

        public virtual void Add(T domainObject)
        {
            Validate(domainObject);
            try
            {
                using (ISession session = SessionProvider.GetSession())
                {
                    using(ITransaction transaction = session.BeginTransaction())
                    {
                        session.Save(domainObject);
                        transaction.Commit();
                    }
                }
            }
            catch(GenericADOException ex)
            {
                throw new DataException(ex.Message, ex);
            }
        }

        public void Delete(T domainObject)
        {
            try
            {
                using (ISession session = SessionProvider.GetSession())
                {
                    using (ITransaction transaction = session.BeginTransaction())
                    {
                        session.Delete(domainObject);
                        transaction.Commit();
                    }
                }
            }
            catch (GenericADOException ex)
            {
                throw new DataException(ex.Message, ex);
            }
        }

        public void Save(T domainObject)
        {
            Validate(domainObject);
            
            try
            {
                using (ISession session = SessionProvider.GetSession())
                {
                    using(ITransaction transaction = session.BeginTransaction())
                    {
                        session.Update(domainObject);
                        transaction.Commit();
                    }
                }
            }
            catch (GenericADOException ex)
            {
                throw new DataException(ex.Message, ex);
            }
        }

        public IList<T> GetAll()
        {
            try
            {
                using (ISession session = SessionProvider.GetSession())
                {
                    IList<T> list = session.CreateCriteria(typeof(T))
                        .List<T>();
                    return list;
                }
            }
            catch (GenericADOException ex)
            {
                throw new DataException(ex.Message, ex);
            }
        }

        public T GetById(int id)
        {
            try
            {
                using (ISession session = SessionProvider.GetSession())
                {
                    T domainObject = session.CreateCriteria(typeof(T))
                       .Add(Expression.Eq("Id", id))
                       .UniqueResult<T>();

                    return domainObject;
                }
            }
            catch (GenericADOException ex)
            {
                throw new DataException(ex.Message, ex);
            }
        }
    }
}